package greensimulation;

import javafx.animation.Interpolator;
import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Parent;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseEvent;
import javafx.scene.paint.Color;
import javafx.scene.paint.CycleMethod;
import javafx.scene.paint.LinearGradient;
import javafx.scene.paint.Paint;
import javafx.scene.paint.Stop;
import javafx.scene.shape.Line;
import javafx.scene.shape.Rectangle;
import javafx.util.Duration;

public class Computer extends Parent {
    private static final Duration DURATION500 = Duration.valueOf(500);
    private static final Interpolator INTERPOLATOR = Interpolator.EASE_BOTH;
    private final Image computer_image = new Image(Main.class.getResource("images/computer.jpg").toExternalForm(), 200, 150, true, true, false);
    private ImageView imageview;
    private Rectangle inRectangle;
    private double freq;
    private double consoHidle;
    private double consoFull;
    private double consoPerThread;
    private long threadNumber;
    private double bootTime;
    private double consoBoot;
    public boolean isPoweredOn;
    //private LinearGradient lineargradient;
    private Rectangle rectanglePowerOff;
    private Group totalGroup = new Group();
    private Group separations = new Group();
    private double minGreenRatio = 0;
    private double maxGreenRatio = 1;
    private double minPerfRatio = 0;
    private double maxPerfRatio = 1;
    private double rectangleWidth = 154;
    private double rectangleHeigth = 96;
    private double rectangleOffsetX = 12;
    private double rectangleOffsetY = 11;
    
    public Computer() {
        imageview = new ImageView();
        imageview.setImage(computer_image);
        imageview.setVisible(true);
        inRectangle = new Rectangle(rectangleWidth, rectangleHeigth);
        inRectangle.setLayoutX(rectangleOffsetX);
        inRectangle.setLayoutY(rectangleOffsetY);
        inRectangle.setVisible(true);
        rectanglePowerOff = new Rectangle(rectangleWidth, rectangleHeigth);
        rectanglePowerOff.setLayoutX(rectangleOffsetX);
        rectanglePowerOff.setLayoutY(rectangleOffsetY);
        rectanglePowerOff.setVisible(true);
        rectanglePowerOff.setOpacity(0);
        
        rectanglePowerOff.setOnMouseClicked(new EventHandler<MouseEvent>(){
            public void handle(MouseEvent e){
                switchPower();
            }
        });
        
        getChildren().addAll(totalGroup);
        totalGroup.getChildren().addAll(imageview, inRectangle, separations, rectanglePowerOff);
        
        isPoweredOn = false;
        
        freq = 1 + 2*Math.random();                     // 1  -> 3
        consoHidle = 20 + 30*Math.random();             // 20 -> 50
        threadNumber = Math.round(2+4*Math.random());   // 2 -> 6
        consoFull = 4*consoHidle;                       // 80 -> 200
        consoPerThread = (consoFull-consoHidle)/(double)threadNumber;
        bootTime = 30 + 20*Math.random() + 20/freq;
        consoBoot = consoFull + 10;
        
        update();
    }
    
    public double getGreenRatio(){
        double greenCoef = consoFull/(freq*(double)threadNumber);   // 40/9 -> 100
        double minGreen = 40d/9d;
        double maxGreen = 100d;
        return (greenCoef-minGreen)/(maxGreen-minGreen);
    }
    
    public double getPerfRatio(){
        double perfCoef = (freq*(double)threadNumber);
        return (perfCoef-2d)/16d;
    }
    
    private double getCorrectedGreenRatio(){
        double greenRatio = getGreenRatio();
        return (greenRatio - minGreenRatio) / (maxGreenRatio - minGreenRatio);
    }
    
    private double getCorrectedPerfRatio(){
        double perfRatio = getPerfRatio();
        return (perfRatio - minPerfRatio) / (maxPerfRatio - minPerfRatio);
    }
    
    public void setMinMaxGreenPerfRatio(double minGreen, double maxGreen,
                                    double minPerf,  double maxPerf){
        this.minGreenRatio = minGreen;
        this.maxGreenRatio = maxGreen;
        this.minPerfRatio = minPerf;
        this.maxPerfRatio = maxPerf;
        update();
    }
    
    private void update(){
        double greenCoefRatio = getCorrectedGreenRatio();
        double redRatio = 1.5*greenCoefRatio - 0.5;
        double greenRatio = 1.5*(1-greenCoefRatio) - 0.5;
        redRatio = (redRatio < 0) ? 0 : redRatio;
        greenRatio = (greenRatio < 0) ? 0 : greenRatio;

        double perfCoefRatio = getCorrectedPerfRatio();
        double redRatioPerf = 1.5*(1-perfCoefRatio) - 0.5;
        double greenRatioPerf = 1.5*perfCoefRatio - 0.5;
        redRatioPerf = (redRatioPerf < 0) ? 0 : redRatioPerf;
        greenRatioPerf = (greenRatioPerf < 0) ? 0 : greenRatioPerf;        
        
        Stop[] stops = new Stop[] {
            new Stop(0, new Color(redRatio, greenRatio, 0, 1)), 
            new Stop(1, new Color(redRatioPerf, greenRatioPerf, 0, 0.5))};
        LinearGradient lineargradient = new LinearGradient(0, 0, 1, 0, true, CycleMethod.NO_CYCLE, stops);
        inRectangle.setFill(lineargradient);
        
        Stop[] stops2 = new Stop[] {
            new Stop(0, Color.BLACK),
            new Stop(0.5, Color.WHITE),
            new Stop(1, Color.BLACK)};
        LinearGradient lg2 = new LinearGradient(0, 0, 0, 1, true, CycleMethod.NO_CYCLE, stops2);
        rectanglePowerOff.setFill(lg2);
        
        separations.setOpacity(0);
        for(int i=1 ; i<threadNumber ; i++){
//            Rectangle tmp = new Rectangle(
//                    rectangleOffsetX+rectangleWidth*i/threadNumber, 
//                    rectangleOffsetY, 1d, rectangleHeigth
//                    );
            double x = rectangleOffsetX+rectangleWidth*i/threadNumber;
            double y = rectangleOffsetY;
            Line tmp = new Line(x, y, x, y+rectangleHeigth);
            separations.getChildren().addAll(tmp);
        }
        
        isPoweredOn = true;
        switchPower();
    }
 
    
    public Rectangle getRectangle(){
        return inRectangle;
    }
    
    public void switchPower(){
        isPoweredOn = !isPoweredOn;

        double newOpacity = isPoweredOn ? 0d : 0.5d;
        double newOpacityR = isPoweredOn ? 1d : 0.5d;
        double newOpacityS = isPoweredOn ? 1d : 0d;
        
        Timeline timeline = new Timeline();
        final ObservableList<KeyFrame> keyFrames = timeline.getKeyFrames();
        keyFrames.addAll(
                new KeyFrame(DURATION500, new KeyValue(rectanglePowerOff.opacityProperty(), newOpacity, INTERPOLATOR)),
                new KeyFrame(DURATION500, new KeyValue(inRectangle.opacityProperty(), newOpacityR, INTERPOLATOR)),
                new KeyFrame(DURATION500, new KeyValue(separations.opacityProperty(), newOpacityS, INTERPOLATOR))
                );
        timeline.play();
    }
    
}
